﻿using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Behaviorize.CodeGenerator.CodeModel
{
	public class Scenario
	{
		public string Name { get; internal set; }
		public IList<StepDefinition> Given { get; internal set; }
		public IList<StepDefinition> When { get; internal set; }
		public IList<StepDefinition> Then { get; internal set; }
		public virtual Dictionary<string, List<object>> Examples { get; internal set; }

		private static void GetStepsAsText(string first, string following, StringBuilder spec, IList<StepDefinition> steps)
		{
			for (int i = 0; i < steps.Count; i++)
			{
				var step = steps[i];
				spec.AppendFormat("\t{0} {1} \n", i == 0 ? first : following, step);
			}
		}

		private static string GetStepsAsCode(string first, string following, IList<StepDefinition> steps, Dictionary<string, object> exampleRow)
		{
			StringBuilder code = new StringBuilder();

			for (int i = 0; i < steps.Count; i++)
			{
				var step = steps[i];

				code.AppendFormat("\t\t\t{0}({1})", i == 0 ? first : following, step.GetInvokationExpression(exampleRow));
			}

			return code.ToString();
		}

		internal string RenderCode()
		{
			StringBuilder code = new StringBuilder();

			if (Examples.Count == 0)
			{
				code.AppendLine("\t\t\tnew Scenario()");
				code.AppendLine(GetStepsAsCode("\t.Given", "\t.And", Given, null));
				code.AppendLine(GetStepsAsCode("\t.When", "\t.And", When, null));
				code.AppendLine(GetStepsAsCode("\t.Then", "\t.And", Then, null));
				code.AppendLine("\t\t\t\t.Verify();");
			}
			else
			{
				code.Append("\t\t\tvar spec = new Scenario();\r\n\r\n");

				for (int y = 0; y < Examples[Examples.Keys.First()].Count; y++)
				{
					var exampleRow = new Dictionary<string, object>();

					foreach (string column in Examples.Keys)
					{
						exampleRow[column] = Examples[column][y];
					}

					code.AppendLine(GetStepsAsCode("spec.Given", "\t.And", Given, exampleRow));
					code.AppendLine(GetStepsAsCode("\t.When", "\t.And", When, exampleRow));
					code.AppendLine(GetStepsAsCode("\t.Then", "\t.And", Then, exampleRow) + ";");
					code.AppendLine();
				}

				code.Append("\t\t\tspec.Verify();\r\n\r\n");
			}

			return code.ToString();
		}

		public override string ToString()
		{
			StringBuilder sb = new StringBuilder();

			sb.AppendLine(string.Format("Scenario: {0}", Name));
			GetStepsAsText("Given", "and", sb, Given);
			GetStepsAsText("when", "and", sb, When);
			GetStepsAsText("then", "and", sb, Then);

			return sb.ToString();
		}
	}
}